SPB Git forge

spb/immbot-ai

Public
1commits 1branches 0releases
1.5 MBsize
maindefault branch
20 days agolast push
TypeScript 98.3% CSS 0.9% Shell 0.7%
4.0 KB · 89 lines typescript
Raw Blame History
1// Plan d'étude personnalisé : génération, consultation, progression (items cochés).2import { NextResponse } from "next/server";3import { z } from "zod";4import { apiError, parseBody, requireEnrollment } from "@/lib/api.ts";5import { assertSameOrigin, requireUser } from "@/lib/auth/session.ts";6import { get, run } from "@/lib/db/index.ts";7import { generatePlan } from "@/lib/learning/plan.ts";8import { normalizeCourse } from "@/lib/learning/helpers.ts";9import { logActivity } from "@/lib/usage.ts";1011export async function GET(_req: Request, ctx: { params: Promise<{ course: string }> }) {12  try {13    const user = await requireUser();14    const course = normalizeCourse((await ctx.params).course);15    requireEnrollment(user.id, course);16    const plan = get<{ id: number; exam_date: string; config: string; plan: string; created_at: string }>(17      "SELECT id, exam_date, config, plan, created_at FROM study_plans WHERE user_id = ? AND course_code = ? AND active = 1 ORDER BY id DESC LIMIT 1",18      user.id, course19    );20    return NextResponse.json({21      plan: plan ? { id: plan.id, examDate: plan.exam_date, config: JSON.parse(plan.config), days: JSON.parse(plan.plan), createdAt: plan.created_at } : null,22    });23  } catch (e) {24    return apiError(e);25  }26}2728const createSchema = z.object({29  action: z.literal("create"),30  examDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),31  weekdays: z.array(z.number().int().min(0).max(6)).min(1),32  minutesPerSession: z.number().int().min(20).max(360),33  weeksScope: z.tuple([z.number().int().min(1).max(14), z.number().int().min(1).max(14)]),34});35const toggleSchema = z.object({36  action: z.literal("toggle"),37  planId: z.number().int().positive(),38  date: z.string(),39  itemIndex: z.number().int().min(0),40  done: z.boolean(),41});4243export async function POST(req: Request, ctx: { params: Promise<{ course: string }> }) {44  try {45    await assertSameOrigin();46    const user = await requireUser();47    const course = normalizeCourse((await ctx.params).course);48    requireEnrollment(user.id, course);49    const body = await parseBody(req, z.discriminatedUnion("action", [createSchema, toggleSchema]));5051    if (body.action === "create") {52      if (new Date(body.examDate) <= new Date()) {53        return NextResponse.json({ error: "La date d'examen doit être dans le futur." }, { status: 400 });54      }55      const days = generatePlan(user.id, course, {56        examDate: body.examDate,57        weekdays: body.weekdays,58        minutesPerSession: body.minutesPerSession,59        weeksScope: body.weeksScope,60      });61      if (!days.length) return NextResponse.json({ error: "Aucun jour disponible avant l'examen avec ces choix." }, { status: 400 });62      run("UPDATE study_plans SET active = 0 WHERE user_id = ? AND course_code = ?", user.id, course);63      const r = run(64        "INSERT INTO study_plans (user_id, course_code, exam_date, config, plan, active) VALUES (?, ?, ?, ?, ?, 1)",65        user.id, course, body.examDate,66        JSON.stringify({ weekdays: body.weekdays, minutesPerSession: body.minutesPerSession, weeksScope: body.weeksScope }),67        JSON.stringify(days)68      );69      logActivity(user.id, "plan", course, 60);70      return NextResponse.json({ ok: true, planId: Number(r.lastInsertRowid), days });71    }7273    // toggle74    const plan = get<{ id: number; plan: string }>(75      "SELECT id, plan FROM study_plans WHERE id = ? AND user_id = ? AND course_code = ?",76      body.planId, user.id, course77    );78    if (!plan) return NextResponse.json({ error: "Plan introuvable." }, { status: 404 });79    const days = JSON.parse(plan.plan) as { date: string; items: { done?: boolean }[] }[];80    const day = days.find((d) => d.date === body.date);81    if (!day || !day.items[body.itemIndex]) return NextResponse.json({ error: "Élément introuvable." }, { status: 404 });82    day.items[body.itemIndex].done = body.done;83    run("UPDATE study_plans SET plan = ? WHERE id = ?", JSON.stringify(days), plan.id);84    return NextResponse.json({ ok: true });85  } catch (e) {86    return apiError(e);87  }88}89